/*
 * Copyright 2003-2007 (c) Live Media Pty Ltd. <argot@einet.com.au> 
 *
 * This software is licensed under the Argot Public License 
 * which may be found in the file LICENSE distributed 
 * with this software.
 *
 * More information about this license can be found at
 * http://www.einet.com.au/License
 * 
 * The Developer of this software is Live Media Pty Ltd,
 * PO Box 4591, Melbourne 3001, Australia.  The license is subject 
 * to the law of Victoria, Australia, and subject to exclusive 
 * jurisdiction of the Victorian courts.
 */

package com.colony.remote.rpc;

import java.io.IOException;
import java.util.HashMap;

import com.argot.TypeException;
import com.argot.TypeInputStream;
import com.argot.TypeLibraryReader;
import com.argot.TypeLibraryWriter;
import com.argot.TypeMap;
import com.argot.TypeOutputStream;
import com.argot.TypeReader;
import com.argot.TypeWriter;
import com.argot.common.BigEndianUnsignedByte;
import com.argot.common.BigEndianUnsignedShort;
import com.argot.remote.MetaLocation;
import com.argot.remote.MetaMethod;
import com.argot.remote.MetaParameter;


public class RpcMetaRequest 
implements TypeLibraryReader, TypeLibraryWriter
{
	public static final String TYPENAME = "remote.rpc.request";

	private static class RpcMetaRequestReader
	implements TypeReader
	{
		private TypeReader _metaLocation;
		private TypeReader _uint16;
		private TypeReader _uint8;
		private HashMap _methodCache;
		
		public RpcMetaRequestReader( TypeMap map )
		throws TypeException
		{
			_metaLocation = map.getReader(map.getId(MetaLocation.TYPENAME));
			_uint16 = map.getReader(map.getId(BigEndianUnsignedShort.TYPENAME));
			_uint8 = map.getReader(map.getId(BigEndianUnsignedByte.TYPENAME));
			_methodCache = new HashMap();
		}
		
		public Object read(TypeInputStream in) 
		throws TypeException, IOException 
		{
			MetaLocation mObject = (MetaLocation) _metaLocation.read(in);
			
			Integer mId = (Integer) _uint16.read(in);
			MetaMethod mMethod = (MetaMethod) _methodCache.get(mId);
			if (mMethod==null)
			{
				int systemMid = in.getTypeMap().getSystemId( mId.intValue() );
				mMethod = (MetaMethod) in.getTypeMap().getLibrary().getStructure( systemMid );
				_methodCache.put(mId, mMethod);
			}
			
			MetaParameter[] responseTypes = mMethod.getResponseTypes();
			
			Short size = (Short) _uint8.read(in);
			Object[] objs = new Object[ size.intValue() ];
			for ( int x=0; x<size.intValue(); x++ )
			{
				Integer id = (Integer) _uint16.read(in);
				int sId = in.getTypeMap().getSystemId( id.intValue() );
				if ( sId != responseTypes[x].getParamType() )
				{
					// the type we expected wasn't there.
				}
				objs[x] = in.readObject( id.intValue() );
			}
			return new RpcMetaMethodRequest( mObject, mMethod, objs );
		}
	}
	public TypeReader getReader(TypeMap map) 
	throws TypeException 
	{
		return new RpcMetaRequestReader(map);
	}
	
	private static class RpcMetaRequestWriter
	implements TypeWriter
	{
		private TypeWriter _metaLocation;
		private TypeWriter _uint8;
		private TypeWriter _uint16;
		
		public RpcMetaRequestWriter(TypeMap map)
		throws TypeException
		{
			_metaLocation = map.getWriter(map.getId(MetaLocation.TYPENAME));
			_uint8 = map.getWriter(map.getId(BigEndianUnsignedByte.TYPENAME));
			_uint16 = map.getWriter(map.getId(BigEndianUnsignedShort.TYPENAME));
		}
		
		public void write(TypeOutputStream out, Object o) 
		throws TypeException, IOException 
		{
			RpcMetaMethodRequest request = (RpcMetaMethodRequest) o;
			
			_metaLocation.write(out, request.getLocation());
			
			int mappedMethodId =  out.getTypeMap().getId( request.getMetaMethod().getMemberTypeId());
			_uint16.write(out, new Integer( mappedMethodId ));
			
			MetaParameter[] requestTypes = request.getMetaMethod().getRequestTypes();
			Object[] args = request.getArguments();
			
			_uint8.write(out, new Integer( requestTypes.length ));
			for( int x=0; x< requestTypes.length; x++ )
			{
				int mappedId = out.getTypeMap().getId( requestTypes[x].getParamType() );
				_uint16.write(out, new Integer( mappedId ) );
				
				out.writeObject( mappedId, args[x] );
			}
		}
	}

	public TypeWriter getWriter(TypeMap map) 
	throws TypeException 
	{
		return new RpcMetaRequestWriter(map);
	}

}
